// Promise有状态,pending,fulfilled,rejected
//创建实例的时候,要丢一个函数进去,形参是resolve,reject两个方法
//调用resolve,就是把pending状态改为fulfilled,reject()是改为rejected,一旦状态更改后,就不可以再改了

const { xor } = require("lodash")

//先定义三个状态
const PENDING='pending'
const FULFILLED='fulfilled'
const REJECTED='rejected'

class Mypromise{
  constructor(executor){
    try {
      executor(this.reolve,this.reject)
    } catch (error) {//执行器如果发生错误,捕获错误,丢给catch
      this.reject(error)
    }
  }
  status=PENDING
  //成功的值
  value=undefined
  //失败的原因
  reason=undefined
  // 预存储成功的回调和失败的回调
  successCallback=[]
  failCallback=[]
  reolve=value=>{//这个value是成功之后的值
    //用来更改状态
    if(this.status!==PENDING)return
    this.status=FULFILLED
    //保存成功的值,给then的成功回调
    this.value=value
    // 如果有成功的回调,就调用一下
    // while(this.successCallback.length){
    //   this.successCallback.shift()(this.value)
    // }
    while(this.successCallback.length){
      this.successCallback.shift()()
    }
    // if(this.successCallback)this.successCallback(this.value)
  }
  reject=reason=>{//reason是失败的原因
    if(this.status!==PENDING)return
    //更改为失败的状态
    this.status=REJECTED
    //保存失败的值,给then的失败回调
    this.reason=reason
    //如果有失败的回调,就调用一下
    // if(this.failCallback)this.failCallback(this.reason)
    // while(this.failCallback.length){
    //   this.failCallback.shift()(this.reason)
    // }
    while(this.failCallback.length){
      this.failCallback.shift()()
    }
  }

  //实例身上的then和catch方法
  //then的参数是两个函数,第一函数是正确的时候回调,第二个参数是错误时候的回调,then的返回是新的promise,实现链式调用
  //成功回调有个参数,是成功之后的值
  //失败回调有个参数,是失败的原因
  then(successCallback,failCallback){
    //如果then没有参数,则默认补充一个参数,把值原样丢给下一个then
    successCallback=successCallback?successCallback:value=>value
    failCallback=failCallback?failCallback:reason=>{throw reason}
    let promise2=new Mypromise((resolve,reject)=>{
      if(this.status===FULFILLED){
        setTimeout(()=>{//因为此时没有promise,所以异步一下
          try {//捕获成功回调的错误,丢给下一个then
            let res=successCallback(this.value)
            //获取上一个then方法的回调返回值,并传递给下一个then的回调
            // resolve(res)//如果res不是promise对象,那就直接丢出去给下一个then,如果是一个promise对象,根据对象的状态,获取对应的值,然后丢出去
            resolvePromise(promise2,res,resolve,reject)
          } catch (error) {
            reject(error)
          }
        },0)
      }else if(this.status===REJECTED){
        setTimeout(()=>{//因为此时没有promise,所以异步一下
          try {//捕获成功回调的错误,丢给下一个then
            let res=failCallback(this.value)
            //获取上一个then方法的回调返回值,并传递给下一个then的回调
            // resolve(res)//如果res不是promise对象,那就直接丢出去给下一个then,如果是一个promise对象,根据对象的状态,获取对应的值,然后丢出去
            resolvePromise(promise2,res,resolve,reject)
          } catch (error) {
            reject(error)
          }
        },0)
      }else{
        //如果还是pending的情况
        //说明是异步代码
        //先预存储成功回调和失败回调
        this.successCallback=this.push(()=>{
          // successCallback()
          setTimeout(()=>{//因为此时没有promise,所以异步一下
            try {//捕获成功回调的错误,丢给下一个then
              let res=successCallback(this.value)
              //获取上一个then方法的回调返回值,并传递给下一个then的回调
              // resolve(res)//如果res不是promise对象,那就直接丢出去给下一个then,如果是一个promise对象,根据对象的状态,获取对应的值,然后丢出去
              resolvePromise(promise2,res,resolve,reject)
            } catch (error) {
              reject(error)
            }
          },0)
        })
        this.failCallback=this.push(()=>{
          // failCallback()
          setTimeout(()=>{//因为此时没有promise,所以异步一下
            try {//捕获成功回调的错误,丢给下一个then
              let res=failCallback(this.value)
              //获取上一个then方法的回调返回值,并传递给下一个then的回调
              // resolve(res)//如果res不是promise对象,那就直接丢出去给下一个then,如果是一个promise对象,根据对象的状态,获取对应的值,然后丢出去
              resolvePromise(promise2,res,resolve,reject)
            } catch (error) {
              reject(error)
            }
          },0)
        })
      }
    })
    return promise2
  }


  // all静态方法,接收数组,数组的元素是promise或者普通元素,返回值是一个全新的promise,调用then时的结果也是数组,顺序和传入数组的顺序相同
  static all(arr){
    let res=[]
    let num=0
    return new Mypromise((resolve,reject)=>{
      function add(index,value){
        res[index]=value
        num++
        if(num===arr.length)resolve(res)  //把结果丢出去
      }
      for(let i=0,i<arr.length,i++){
        let current=arr[i]
        if(current instanceof Mypromise){
          //是个promise对象
          current.then(value=>add(i,value),reason=>reject(reason))
        }else{
          //不是个promise对象,直接丢到结果数组中
          add(i,current)
        }
      }
    })
  }

  // resolve方法,接受promise或者普通值
  static resolve(value){
    if(value instanceof Mypromise){
      return value
    }else{
      return new Mypromise(resolve=>resolve(value))
    }
  }

  //补上catch方法
  catch(failCallback){
    return this.then(undefined,failCallback)
  }

  // finally
  // 不管状态是什么,finally一定要执行一次
  // 要返回promise对象
  finally(callback){
    return this.then(value=>{
      // callback()这样就直接丢出去了,如果callback的返回值是个异步,就有问题了
      return Mypromise.resolve(callback()).then(()=>value)
      // return value
    },(reason)=>{
      // callback()
      // throw reason
      return Mypromise.resolve(callback()).then(()=>{throw reason})
    })
  }
}

function resolvePromise(promise2,res,resolve,reject){
  if(promise2===res){
    return reject('自己返回了自己')
  }
  
  //判断res是不是promise对象
  if(res instanceof Mypromise){//判断res是不是MyPromise的一个实例
    res.then(resolve,reject)
  }else{
    resolve(res)
  }
}

let promise=new Mypromise((resolve,reject)=>{
  // resolve('成功')
  reject('失败')
})
promise.then(value=>{
  console.log(value);
},reason=>{
  console.log(reason);
})
